perm filename ALAID.PAL[HAL,HE]3 blob sn#200967 filedate 1976-02-09 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00014 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	
C00003 00003	Fields and data:  ALDOPS, BRKTAB
C00006 00004	 INTERP
C00009 00005	 TYPVAL
C00013 00006	I/O routines:  TYPR50, INCHR, INOCT, INR50
C00017 00007	 BRACE
C00021 00008		take care of break case
C00027 00009	 NEWBRK, FNDBRK
C00029 00010	 TPPSOP
C00032 00011	 TYPADR, TYPOFS, INADR, INOFS
C00034 00012	  Data structures:  Notes, note cells, message buffers
C00035 00013	  LWAIT, SWAIT, LISTEN, SEND
C00038 00014	  DOGTBUF, USEFUB, RELBUF
C00040 ENDMK
C⊗;
COMMENT ⊗
.TITLE  Test of ALAID

.INSRT HALHED.PAL[HAL,HE]
.INSRT K2DEF.PAL[11,SYS]
.INSRT HALIO.PAL[HAL,HE]
;⊗
;Fields and data:  ALDOPS, BRKTAB

COMMENT ⊗ ALAID information resides in the ALDOPS table parallel to
the INTOPS table.  Each psuedo-op has these fields: ⊗

	II == 0
	XX ALDFLG	;Holds bits indicating status of tracing
	    ALDBRK == 1	; Break bit.  When set, break on this psop.
	    ALDTRC == 2	; Tracing bit.  When set, trace this psop.
	XX ALDARG	;Encoding the types of arguments taken by this psop.
	XX ALDPNM	;The RAD50 print name of the psop.  Two words
	    II == II + 2
	OPSLTH == II/2	;Number of words in each ALDOPS entry

	.MACRO MAKEOP CNAME, ANAME, TYPES
	    ;Compiler name, Address name, Types of arguments
	II == .
	0		;ALDFLG
            III == 0
            II2 == 1
                .IRP ARG,<TYPES>
                    .IF NB ARG
                    III == II2*ARG + III
                    II2 == 8*II2
                    .ENDC
                .ENDM
	III		;ALDARG

	.RAD50 /ANAME/	;ALDPNM
	. = II + OPSLTH	+ OPSLTH;Just in case the ANAME was funny
	.ENDM

	A == 1
	LA == 2
	O == 3
	LO == 4
	N == 5
	R50 == 6

; The interpreter operation debug table
ALDOPS: MAKEOP XINVALID,INVALD		;Illegal instruction
	.INSRT	INTOPS.PAL[HAL,HE]

COMMENT ⊗ There is a fixed number of available bracepoints.  (Break
or trace points).  When a bracepoint is in place, the old contents of
the instruction are stored in the breakpoint table.  Bracepoints are
always kept in place. ⊗
	II == 0
	XX OLDPSOP 	;Saved contents of psinstruction
	XX OLDADR	;Where it comes from
	XX BRCWHA	;Flags saying what to do.
	    ALDBRK == 1 ; Break bit.  When set, this is a break point.
	    ALDTRC == 2	; Tracing bit.  When set, this is a tracepoint.
	BRKLTH == II/2	;Number of words in each entry

BRKNO == 10		;Number of breakpoints available
BRKTAB:	.BLKW BRKLTH*BRKNO
BRKDUM:	.BLKW BRKLTH	;One dummy break table entry for bad entries
	
; INTERP

	.MACRO BMPIPC	;
	ADD #2,IPC(R4)	;Bump IPC
	.ENDM		;

COMMENT ⊗ This is the interpreter loop which replaces the one in
INTERP.PAL.  It does bounds checking for the instruction, then
catches single step, special traps or traces on this instruction
type, then breakpoints or tracepoints in the code.  Finally it calls
the appropriate interpeter routine.  ⊗

INTERP:
	MOV R3,R0	;Save the limit of the interpreter stack for error checking.
	SUB #INSTSZ-2,R0	
	MOV R0,-(SP)	;
INT1:	CMP R3,(SP)	;Interpreter stack overflow?
	BGE INT3	;No.  Go to next instruction.
	HALERR INTMS3	;Yes.  Complain.
INT3:	MOV @IPC(R4),R0	;R0 ← next instruction
	BLE INVALID	;Instruction out of range
	CMP R0,#INSEND	;Is instruction too large?
	BLE INT2	;No.
INVALID:HALERR INTMS1	;Yes. complain.
INT2:	BMPIPC		;Bump IPC

	;catch single step
	BIT #ALDSS,DEBMOD(R4)	;Single step?
	BEQ INT4	;No
INT5:	JSR PC,BRACE	;R0 ← proper psop to execute
	BR  INTDO	;Now do the instruction

	;catch break on instruction type
INT4:	MOV #OPSLTH,R1	;
	MUL R0,R1	;
	ADD #ALDOPS,R1	;
	MOV R1,R2	;R2 ← pointer into ALDOPS
	BIT #ALDBRK,ALDFLG(R2)	;Break?
	BNE INT5	;Yes.

	;catch brace instruction
	CMP #XBRACE,R0	;Is it a brace instruction?
	BEQ INT5	;Yes.

	;catch trace on instruction type
	BIT #ALDTRC,ALDFLG(R2)	;Trace?
	BEQ INTDO	;No.
	JSR PC,TRACE	;Yes.

INTDO:	JSR PC,@INTOPS(R0)	;Call the appropriate routine
	BR  INTCPL(R0)	;R0 should have an completion code.  Branch accordingly.

INTCPL: BR  INT1	;No error.  Repeat.
	HALERR INTMS2	;Error.  Complain.
	BR INT1		;And repeat.

INTMS1:	ASCIE /INTERPRETER INSTRUCTION OUT OF RANGE/
INTMS2:	ASCIE /INTERPRETED INSTRUCTION RETURNED FAILURE/
INTMS3:	ASCIE /INTERPRETER STACK OVERFLOW/
; TYPVAL

TYPVAL:
COMMENT ⊗ R0 points to a value cell.  Prints it according to its
type.  Requires the floating package.  ⊗
	MOV R2,-(SP)	;Save R2
	MOV R0,R2	;R2 ← LOC[value cell]
	MOV #CRLFX,R0	;CRLF
	JSR PC,TYPSTR	;
	MOVB TAGID(R2),R1
	CMPB #SCLID,R1	;A scalar?
	BEQ TYPVL1	;
	CMPB #VCTID,R1	;A vector?
	BEQ TYPVL4	;
	CMPB #TRNID,R1	;A trans?
	BEQ TYPVL5	;
TYPVL1:	MOV #SNAME,R0	;
	JSR PC,TYPSTR	;"SCALAR "
	MOV #OUTBUF,R0	;
TYPVL2:	LDF (R2),AC0	;
	JSR PC,CVG	;
	MOV #OUTBUF,R0	;
	JSR PC,TYPSTR	;
TYPVL3:	MOV #CRLFX,R0	;CRLF
	JSR PC,TYPSTR	;
	MOV (SP)+,R2	;Restore R2
	RTS PC		;Done
TYPVL4:	MOV #VNAME,R0	;
	JSR PC,TYPSTR	;"VECTOR "
	MOV #OUTBUF,R0	;
	LDF (R2)+,AC0	;
	JSR PC,CVG	;
	LDF (R2)+,AC0	;
	JSR PC,CVG	;
	BR  TYPVL2	;Bum code for last field.
TYPVL5:	MOV #TNAME,R0	;
	JSR PC,TYPSTR	;"TRANS "
	MOV R3,-(SP)	;Save R3
	MOV #4,R3	;R3 ← Number of rows
TYPVL6:	MOV #CRLFX,R0	;
	JSR PC,TYPSTR	;
	MOV #OUTBUF,R0	;
	LDF (R2),AC0	;
	JSR PC,CVG	;
	LDF 20(R2),AC0	;
	JSR PC,CVG	;
	LDF 40(R2),AC0	;
	JSR PC,CVG	;
	LDF 60(R2),AC0	;
	JSR PC,CVG	;
	MOV #OUTBUF,R0	;
	JSR PC,TYPSTR	;
	ADD #4,R2	;Next row
	SOB R3,TYPVL6	;
	MOV (SP)+,R3	;Restore R3
	BR  TYPVL3	;Go to the exit stage

SNAME:	ASCIE /SCALAR /
VNAME:	ASCIE /VECTOR /
TNAME:	ASCIE /TRANS /
;I/O routines:  TYPR50, INCHR, INOCT, INR50

;Type contents of R0 as RAD50
TYPR50:	MOV R0,R1	;Arg in R1
	CLR -(SP)	;Sentinel
	JSR PC,TPR51	;
	TST (SP)+	;
TPR54:	RTS PC		;Done
TPR51:	CLR R0
	DIV #50,R0	;Do one reduction
	BEQ TPR52	;Down to zero yet?
	MOV R1,-(SP)	;Stack remainder.
	MOV R0,R1
	JSR PC,TPR51	;And do it again.
	MOV (SP)+,R1	;R1 ← saved remainder.
TPR52:	TST R1		;Zero?  
	BEQ TPR54	;Yes.  Flush it.
	CMP R1,#33	;Letter, dollar?
	BLT TPRLET	;Yes, letter
	BEQ TPRDOL	;Yes, dollar
	CMP R1,#35	;Percent?
	BEQ TPRPER	;Yes
	ADD #22,R1	;point or number
TPR53:	MOV R1,R0	;Ready to print
	JMP TYPCHR	;TYPCHR will do the returning

TPRLET:	ADD #100,R1
	BR TPR53

TPRDOL:	MOV #'$,R0
	JMP TYPCHR

TPRPER:	MOV #'%,R0
	JMP TYPCHR

;  Waits for a character to be typed, returns it in R0.  Does not echo.
INCHR:	TST OUTSW	;VT05 or console?
	BEQ INCHR2	;console
	TSTB KBIS	;VT05 input ready?
	BNE INCHR1	;Yes.
INCHR3:	SLEEP #1	;No.  Wait a while
	BR INCHR	;And try again
INCHR1:	MOVB KBIR,R0	;Get a character
	BIC #177600,R0	;Make off to make it 7 bits
	RTS PC 		;Done
INCHR2:	MOV IREG,R0	;Get a character
	BEQ INCHR3	;Nothing there
	CLR IREG	;Clear it for next character
	RTS PC		;Done.

INR50:
COMMENT ⊗ Reads an alphameric string, returns the RAD50
representation in R0 and R1.  Any characters after the 6th are lost.
Input terminated by any illegal RAD50 character.  Backspace works.  ⊗

INOCT:
COMMENT ⊗ Reads an octal number, returns it in R0.  Any non-digit
terminates the number.  Backspace will work properly.  Echoes.  ⊗
	MOV R2,-(SP)	;Save R2
	CLR R2		;R2 is the eventual result
INCT3:	JSR PC,INCHR	;R0 ← Character
	CMP #177,R0	;Backspace?
	BNE INCT4	;No
	ASH #-3,R2	;Get rid of last digit
	MOV #DBS,R0	;Peform deleting backspace.  Defined in HALIO
	JSR PC,TYPSTR	;
	BR  INCT3	;Go back.
INCT4:	CMP #'0,R0	;Too small?
	BGT INCT1	;yes
	CMP #'7,R0	;Too large?
	BGE INCT2	;no
INCT1:	MOV #40,R0	;type a trailing " "
	JSR PC,TYPCHR	;
	MOV R2,R0	;R0 ← result
	MOV (SP)+,R2	;Restore R2
	RTS PC		;Done
INCT2:	MOV R0,-(SP)	;Save the character
	JSR PC,TYPCHR	;Echo it
	ASH #3,R2	;Compute new result
	BIC #60,(SP)	;
	ADD (SP)+,R2	;
	BR  INCT3	;And repeat
; BRACE

BRACE:
COMMENT ⊗ 
This routine can be called from anywhere.  It expects that IPC(R4)
has been bumped once since the last instruction was fetched, that is,
the instruction is at IPC(R4)-2.  The currently implemented
operations are:
	DDT		go to DDT, where <alt>P will return to here.
	PROCEED		exits this routine to whoever called it.
	BREAK <adr>	puts a breakpoint at <adr>
	TRACE <adr>	puts a tracepoint at <adr>
	UNBRACE <adr>	removes all bracepoints from <adr>
	EXAMINE <lev-of>examines a variable
	SINGLE STEP	puts a trap on the next instruction, proceeds.
	RESET		remove all breakpoints.
When this routine exits, it has put the psop that it found in R0.  If
the psop was <BREAK>, then the correct equivalent is either <NOOP>
for bad entry or the old psop for bracepoints.  ⊗

	;look up the instruction in the brace table.
	MOV R2,-(SP)	;Save R2
	MOV IPC(R4),R0	;
	SUB #2,R0	;R0 ← address of broken instruction
	JSR PC,FNDBRK	;R1 ← LOC[entry in break table], 0 for none found. R0←R0
	MOV R1,R2	;R2 ← LOC[entry in break table]
	BNE BRK1	;if any
	MOV #BRKDUM,R2	;nope.  use the dummy break instruction.
	MOV (R0),OLDPSOP(R2)	;initialize it.
	MOV R0,OLDADR(R2);
	MOV #ALDBRK,BRCWHA(R2)	;
	BR  BRK2	;We know it is a break

	;see if it is a break or a trace
BRK1:	BIT #ALDSS,DEBMOD(R4)	;Single step?
	BEQ BRK3	;No
	BIC #ALDSS,DEBMOD(R4)	;Turn it off.
	MOV #BRKM00,R0	;":SS:<cr>"
	JSR PC,TYPSTR	;
	BR BRK5		;And otherwise just like a break.
BRK3:	BIT #ALDBRK,BRCWHA(R2)	;Is the break bit on?
	BNE BRK2	;Yes
	BIT #ALDTRC,BRCWHA(R2)	;The trace bit, then?
	BEQ BRK4	;No.

	;take care of trace case
TRACE:	MOV #TRCMS,R0	;Yes.  "<cr>:TRC:"
	JSR PC,TYPSTR	;
	MOV IPC(R4),R0	;
	SUB #2,R0	;R0 ← LOC[psop]
	JSR PC,TYPADR	;Tell where we are.
	MOV OLDPSOP(R2),R0;Tell what psop
	MOV OLDADR(R2),R1;
	ADD #2,R1	;R1 ← LOC[argument(s)]
	JSR PC,TPPSOP	;
	JMP BRKPC1	;Go to the return place.
BRK4:	MOV (SP)+,R2	;Restore R2
	RTS PC		;And exit.

	;take care of break case
BRK2:	MOV #BRKMS1,R0	;":BRK:<cr>"
	JSR PC,TYPSTR	;
BRK5:	MOV IPC(R4),R0	;
	SUB #2,R0	;R0 ← address of broken instruction
	JSR PC,TYPADR	;Tell where we are.
	MOV OLDPSOP(R2),R0;Tell what psop
	MOV OLDADR(R2),R1;
	ADD #2,R1	;R1 ← LOC[argument(s)]
	JSR PC,TPPSOP	;
BRKALD:	MOV #BRKMS0,R0	;Prompt
	JSR PC,TYPSTR	;
	JSR PC,INCHR	;See what the user wants to do.
	CMP #15,R0	;Carriage return?
	BNE BRKPRC	;No.
	MOV #CRLFX,R0	;
	JSR PC,TYPSTR	;
	BR  BRKALD	;
BRKPRC:	CMP #'P,R0	;Proceed?
	BNE BRKDDT	;
	MOV #BRKMS2,R0	;
	JSR PC,TYPSTR	;
BRKPC1:	MOV OLDPSOP(R2),R0	;Load up the psop
	MOV (SP)+,R2	;Restore R2
	RTS PC		;and return
BRKDDT:	CMP #'D,R0	;DDT?
	BNE BRKBRK	;
	MOV #BRKMS3,R0	;
	JSR PC,TYPSTR	;
	BPT		;
	BR BRKALD	;
BRKBRK:	CMP #'B,R0	;Break?
	BNE BRKUNB	;
	MOV #BRKMS4,R0	;
	JSR PC,TYPSTR	;
	JSR PC,INADR	;R0 ← address to put a break point.
	BEQ BRKHUH	;If reasonable
	MOV R0,-(SP)	;Save it
	JSR PC,NEWBRK	;R0 ← nice place in the break table
	BEQ BRKHUH	;If any
	MOV @0(SP),OLDPSOP(R0)
	MOV (SP),OLDADR(R0)
	MOV #ALDBRK,BRCWHA(R0)
	MOV #XBRACE,@(SP)+
	BR BRKALD	;
BRKUNB:	CMP #'U,R0	;Unbreak?
	BNE BRKREF	;
	MOV #BRKMS5,R0	;
	JSR PC,TYPSTR	;
	JSR PC,INADR	;R0 ← address to remove break point from.
	BEQ BRKHUH	;If reasonable
	JSR PC,FNDBRK	;R1 ← LOC[entry in break table], R0 unchanged
	BEQ BRKHUH	;
	MOV OLDPSOP(R1),@OLDADR(R1)	;Replace old instruction
	;note that we do NOT clear the OLDPSOP field; we may need it to proceed.
	CLR OLDADR(R1)	;
	BR BRKALD	;
BRKREF:	CMP #'R,R0	;Refresh?
	BNE BRKVAR	;
	MOV #BRKMS8,R0	;
	JSR PC,TYPSTR	;
	MOV #BRKNO,R1	;R1 ← Count of breakpoints
	MOV #BRKTAB,R0	;R0 ← Pointer into break table
BRKR1:	TST OLDADR(R0)	;A real break, or empty?
	BEQ BRKR2	;Empty
	MOV OLDPSOP(R0),@OLDADR(R0)	;Replace old instruction
	;note that we do NOT clear the OLDPSOP field; we may need it to proceed.
	CLR OLDADR(R0)	;
BRKR2:	SOB R1,BRKR1	;Repeat as necessary
	BR BRKALD	;
BRKVAR:	CMP #'E,R0	;Examine variable?
	BNE BRKSS	;
	MOV #BRKMS6,R0	;
	JSR PC,TYPSTR	;
	JSR PC,INOFS	;R0 ← level-offset of variable
	JSR PC,GETARG	;R0 ← LOC[LOC[graph node]
	MOV (R0),R0	;R0 ← LOC[Graph node]
	MOV GNVAL(R0),R0;R0 ← LOC[value cell]
	JSR PC,TYPVAL	;Print it.
	BR BRKALD	;
BRKSS:	CMP #'S,R0	;Single step?
	BNE BRKTRC	;
	MOV #BRKMS7,R0	;
	JSR PC,TYPSTR	;
	BIS #ALDSS,DEBMOD(R4)	;Set for single step
	BR  BRKPC1	;and just proceed
BRKTRC:	CMP #'T,R0	;Trace?
	BNE BRKHUH	;
	MOV #BRKMS9,R0	;
	JSR PC,TYPSTR	;
	JSR PC,INADR	;R0 ← address to put a trace point.
	BEQ BRKHUH	;If reasonable
	MOV R0,-(SP)	;Save it
	JSR PC,NEWBRK	;R0 ← nice place in the break table
	BEQ BRKHUH	;If any
	MOV @0(SP),OLDPSOP(R0)
	MOV (SP),OLDADR(R0)
	MOV #ALDTRC,BRCWHA(R0)
	MOV #XBRACE,@(SP)+
	JMP BRKALD	;
BRKHUH:	MOV #'π,R0	;
	JSR PC,TYPCHR	;
	JMP BRKALD	;
TRCMS:	ASCIE </
:TRC: />
BRKM00:	ASCIE </
:SS: />
BRKMS0:	ASCIE </NU? />
BRKMS1:	ASCIE </
:BRK: />
BRKMS2:	ASCIE /PROCEED /
BRKMS3:	ASCIE /DDT /
BRKMS4:	ASCIE /BREAK /
BRKMS5:	ASCIE /UNBRACE /
BRKMS6:	ASCIE /EXAMINE VARIABLE /
BRKMS7:	ASCIE /SINGLE STEP /
BRKMS8:	ASCIE /REFRESH /
BRKMS9:	ASCIE /TRACE /
; NEWBRK, FNDBRK

FNDBRK:
COMMENT ⊗ Sets R1 to the entry in the break table which corresponds
to the pseudo-code address in R0.  Does not change R0.  If none is
found, returns 0 in R1.  ⊗
	MOV R2,-(SP)	;Save R2
	MOV #BRKNO,R2	;R2 ← count of possible breakpoints
	MOV #BRKTAB,R1	;R1 ← Pointer into break table
FNDBR1:	CMP R0,OLDADR(R1)
	BEQ FNDBR2	;found
	ADD #2*BRKLTH,R1;not yet found
	SOB R2,FNDBR1	;
	CLR R1		;will never find
FNDBR2:	MOV (SP)+,R2	;Restore R2
	TST R1		;So the caller won't have to.
	RTS PC		;Done

NEWBRK:	
COMMENT ⊗ Finds an empty location in the break table.  If there is
none, returns a 0.  Result is in R0.  ⊗
	MOV #BRKTAB,R0	;First try
FNDB2:	TST OLDADR(R0)	;Anything there?
	BNE FNDB1	;Yes.
	TST R0		;So caller won't have to.
	RTS PC		;No.  All is well
FNDB1:	ADD #2*BRKLTH,R0;Try next one.
	CMP R0,#BRKDUM	;if any
	BLT FNDB2	;
	CLR R0		;none left
	RTS PC		;Done.
; TPPSOP

TPPSOP:
COMMENT ⊗ R0 holds the pseudo-instruction code, R1 points to
the argument (s).  Print out the whole thing, using the information
in the ALDOPS for argument types.  ⊗
	MOV R2,-(SP)	;Save R2
	MOV R3,-(SP)	;Save R3
	MOV R4,-(SP)	;Save R4
	MOV R1,R4	;R4 ← LOC[argument(s)]
	MOV #OPSLTH,R3	;
	MUL R0,R3	;
	ADD #ALDOPS,R3	;R3 ← ponter into ALDOPS
	MOV ALDPNM(R3),R0	;Print name of psop
	JSR PC,TYPR50	;
	MOV ALDPNM+2(R3),R0;
	JSR PC,TYPR50	;
	MOV #40,R0	;" "
	JSR PC,TYPCHR	;
	MOV ALDARG(R3),R2	;R2 ← type of arguments
TPPS3:	MOV R2,R3	;
	BNE TPPS1	;Are there more?
	MOV (SP)+,R4	;No.  Restore R4
	MOV (SP)+,R3	;Restore R3
	MOV (SP)+,R2	;Restore R2
	RTS PC		;Done
TPPS1:	CLR R2		;Yes
	DIV #8,R2	;R2 ← the next type, R3 ← this type
	ADD R3,R3	;Chnage it to byte jump count
	JMP @TPPS0(R3)	;go to the appropriate routine
	BR  TPPS3	;Then do the next one
TPPS0:	0		;
	TPPSA		;
	TPPSLA		;
	TPPSO		;
	TPPSLO		;
	TPPSN		;
TPPSA:	MOV (R4)+,R0	;R0 ← the address
	JSR PC,TYPADR	;Print it
	BR TPPS3	;
TPPSLA:	MOV (R4)+,R0	;R0 ← the next address
	BEQ TPPS3	;if any
	JSR PC,TYPADR	;Print it
	BR  TPPSLA	;And do it again.
TPPSO:	MOV (R4)+,R0	;R0 ← level-offset
	JSR PC,TYPOFS	;Print it
	BR TPPS3	;
TPPSLO:	MOV (R4)+,R0	;R0 ← level-offset
	BEQ TPPS3	;If any
	JSR PC,TYPOFS	;Print it
	BR TPPSLO	;And do it again
TPPSN:	MOV (R4)+,R0	;R0 ← the number
	JSR PC,TYPOCT	;Print it
	MOV #40,R0	;" "
	JSR PC,TYPCHR	;
	BR TPPS3	;
; TYPADR, TYPOFS, INADR, INOFS

TYPADR:  
COMMENT ⊗ R0 holds an address in pseudo-code space.  Print it out
symbolically.  Temporarily, the printout is just octal.  ⊗
	JSR PC,TYPOCT	;
	MOV #40,R0	;
	JSR PC,TYPCHR	;
	RTS PC		;

INADR:	
COMMENT ⊗ Reads from the tty a symbolic address.  Returns the octal
equivalant in R0.  Temporarily just reads in octal.  If the address
is faulty, returns 0. 
⊗
	JSR PC,INOCT	;
	BIT #1,R0	;Odd?
	BNE INADR2	;Yes
	CMP #PCODE,R0	;No. In range?
	BLE INADR1	;Yes
INADR2:	CLR R0		;No.  
INADR1:	TST R0		;So the caller won't have to.
	RTS PC		;

TYPOFS:
COMMENT ⊗ R0 holds a level-offset pair.  Print it out symbolically.
Temporarily, the printout is just "<level,offset>"  ⊗
	MOV R0,-(SP)	;Save the argument
	MOV #'<,R0	;
	JSR PC,TYPCHR	;
	CLR R0		;
	MOVB 1(SP),R0	;The level
	JSR PC,TYPOCT	;
	MOV #',,R0	;
	JSR PC,TYPCHR	;
	CLR R0		;
	MOVB (SP)+,R0	;The offset
	JSR PC,TYPOCT	;
	MOV #'>,R0	;
	JSR PC,TYPCHR	;
	MOV #40,R0	;" "
	JSR PC,TYPCHR	;
	RTS PC		;

INOFS:	
COMMENT ⊗ Reads from the tty a level-offset pair, which it returns in
R0.  Temporarily just reads an octal offset, no level. ⊗
	JSR PC,INOCT	;
	BIC #177400,R0	;Just wipe out any level
	RTS PC		;
;  Data structures:  Notes, note cells, message buffers

;  Notes from 10 to 11;
GETBUF == 1	;
USEBUF == 2	;
RELBUF == 3	;

;  Notes from 11 to 10;
BUFALC == 101	;
TAKBUF == 102	;

;  Offsets in message buffers;
MESID = 0	;
MESTYP = 2	;
MESLTH = 4	;

;  LWAIT, SWAIT, LISTEN, SEND

LWAIT:
COMMENT ⊗ Returns as soon as there is a message from the 10. ⊗
LST2:	TST	NOTB10	;Anything there?
	BNE	LST1	;Yes
	SLEEP	=100	;No, so sleep a while
	BR 	LST2	;And try again
LST1:	RTS	PC	;Done

SWAIT:
COMMENT ⊗ Returns as soon as we can send a message to the 10. ⊗
SWT2:	TST	NOTB11	;Anything there?
	BEQ	SWT1	;No.
	SLEEP	=100	;Yes, so sleep a while
	BR 	SWT2	;And try again
SWT1:	RTS	PC	;Done

LISTEN:
COMMENT ⊗ Interprets the incoming message. ⊗
	JSR 	PC,LWAIT;Wait for a message
	JSR	PC,GTNOTE	;R0 ← LOC[note cell]
	MOV	NOTB10,NTTYPE(R0)	;Fill in the fields of the note.
	MOV	NOTB10+2,ARG1(R0)	;
	MOV	NOTB10+4,ARG2(R0)	;
	CLR	NOTB10		;Indicate that the note has been read.
	MOV	NTTYPE(R0),R1	;R1 ← type of note

	CMP	R1,GETBUF	;GETBUF
	BNE	LST1		;
	JSR	PC,DOGTBUF	;
	BR	LST0		;
LST1:
	CMP	R1,USEBUF	;USEBUF
	BNE	LST2		;
	JSR	PC,DOUSBUF	;
	BR	LST0		;
LST2:
	CMP	R1,RELBUF	;RELBUF
	BNE	LST3		;
	JSR	PC,DORLBUF	;
	BR	LST0		;
LST3:
	HALERR	LSTMES		;Illegal code
	RTS	PC		;

LST0:	JSR	PC,RELNOTE	;Get rid of incoming note
	RTS	PC		;Done

SEND:
COMMENT ⊗ We are to send a note to the 10.  The note is pointed to by
R0.  We must return R0 the same when we return, since the caller will
see to the deletion of the message.  ⊗
	JSR	PC,SWAIT	;Wait until we can send the message.
	MOV	NOTB11+2,ARG1(R0)	;Fill in the fields to the note
	MOV	NOTB11+4,ARG2(R0)	;
	MOV	NOTB11+6,ARG3(R0)	;
	MOV	NOTB11,NTTYPE(R0)	;That effectively sends the note.
	RTS	PC		;Done

;  DOGTBUF, USEFUB, RELBUF

DOGTBUF:
COMMENT ⊗ Called by LISTEN.  The 10 wants us to allocate a buffer.
The size in bytes is in ARG1(R0).  We should respond with BUFALC <size>
<adr>.  ⊗
	MOV	R0,-(SP)	;Save LOC[incoming note]
	MOV	ARG1(R0),R0	;R0 ← size argument
	MOV	R0,-(SP)	;Save size argument
	JSR 	PC,GTFREE	;Get the buffer out of free storage
	MOV	R0,-(SP)	;Save buffer address
	JSR	PC,GTNOTE	;R0 ← LOC[new note to send]
	MOV	#BUFALC,NTTYPE(R0)	;BUFALC
	MOV	(SP)+,ARG2(R0)		;  <adr>
	MOV	(SP)+,ARG1(R0)		;  <size>
	JSR	PC,SEND		;Send the note off.
	JSR	PC,RELNOTE	;Destroy the return message
	MOV	(SP)+,R0	;R0 ← LOC[incoming note]
	RTS	PC		;Done